a11y: Disconnect from buffer signals
authorBenjamin Otte <otte@redhat.com>
Thu, 12 Jan 2012 01:34:27 +0000 (02:34 +0100)
committerBenjamin Otte <otte@redhat.com>
Thu, 12 Jan 2012 03:45:34 +0000 (04:45 +0100)
This way, we don't get crashes when the buffer is still in use after a
TextView gets finalized.

https://bugzilla.gnome.org/show_bug.cgi?id=667632

gtk/a11y/gtktextviewaccessible.c
gtk/a11y/gtktextviewaccessible.h
gtk/gtktextview.c

index 97db302364d5f3f1e0c252a8ccd81f8526893687..52e73ed6700e4a57c6fa2b3098b628564438a714 100644 (file)
@@ -31,9 +31,9 @@
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
 #include "gtktextviewaccessible.h"
+#include "gtk/gtkwidgetprivate.h"
 
 
-static void setup_buffer (GtkTextView           *view,GtkTextViewAccessible *accessible);
 static void       insert_text_cb       (GtkTextBuffer    *buffer,
                                                         GtkTextIter      *arg1,
                                                         gchar            *arg2,
@@ -65,8 +65,6 @@ gtk_text_view_accessible_initialize (AtkObject *obj,
 {
   ATK_OBJECT_CLASS (_gtk_text_view_accessible_parent_class)->initialize (obj, data);
 
-  setup_buffer (GTK_TEXT_VIEW (data), GTK_TEXT_VIEW_ACCESSIBLE (obj));
-
   obj->role = ATK_ROLE_TEXT;
 }
 
@@ -85,10 +83,6 @@ gtk_text_view_accessible_notify_gtk (GObject    *obj,
       editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
       atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, editable);
     }
-  else if (!strcmp (pspec->name, "buffer"))
-    {
-      setup_buffer (GTK_TEXT_VIEW (obj), GTK_TEXT_VIEW_ACCESSIBLE (atk_obj));
-    }
   else
     GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec);
 }
@@ -112,12 +106,50 @@ gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
   return state_set;
 }
 
+static void
+gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible,
+                                        GtkTextBuffer         *old_buffer,
+                                        GtkTextBuffer         *new_buffer)
+{
+  if (old_buffer)
+    {
+      g_signal_handlers_disconnect_matched (old_buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, accessible);
+    }
+
+  if (new_buffer)
+    {
+      g_signal_connect_after (new_buffer, "insert-text", G_CALLBACK (insert_text_cb), accessible);
+      g_signal_connect (new_buffer, "delete-range", G_CALLBACK (delete_range_cb), accessible);
+      g_signal_connect_after (new_buffer, "mark-set", G_CALLBACK (mark_set_cb), accessible);
+    }
+}
+
+static void
+gtk_text_view_accessible_widget_set (GtkAccessible *accessible)
+{
+  gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
+                                          NULL,
+                                          gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))));
+}
+
+static void
+gtk_text_view_accessible_widget_unset (GtkAccessible *accessible)
+{
+  gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible),
+                                          gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))),
+                                          NULL);
+}
+
 static void
 _gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
 {
   AtkObjectClass  *class = ATK_OBJECT_CLASS (klass);
+  GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass);
   GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
 
+  accessible_class->widget_set = gtk_text_view_accessible_widget_set;
+  accessible_class->widget_unset = gtk_text_view_accessible_widget_unset;
+
   class->ref_state_set = gtk_text_view_accessible_ref_state_set;
   class->initialize = gtk_text_view_accessible_initialize;
 
@@ -129,20 +161,6 @@ _gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
 {
 }
 
-static void
-setup_buffer (GtkTextView           *view,
-              GtkTextViewAccessible *accessible)
-{
-  GtkTextBuffer *buffer;
-
-  buffer = gtk_text_view_get_buffer (view);
-
-  /* Set up signal callbacks */
-  g_signal_connect_after (buffer, "insert-text", G_CALLBACK (insert_text_cb), view);
-  g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view);
-  g_signal_connect_after (buffer, "mark-set", G_CALLBACK (mark_set_cb), view);
-}
-
 static gchar *
 gtk_text_view_accessible_get_text (AtkText *text,
                                    gint     start_offset,
@@ -1727,13 +1745,10 @@ insert_text_cb (GtkTextBuffer *buffer,
                 gint           len,
                 gpointer       data)
 {
-  GtkTextView *view = data;
-  GtkTextViewAccessible *accessible;
+  GtkTextViewAccessible *accessible = data;
   gint position;
   gint length;
 
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
-
   position = gtk_text_iter_get_offset (iter);
   length = g_utf8_strlen (text, len);
  
@@ -1748,12 +1763,9 @@ delete_range_cb (GtkTextBuffer *buffer,
                  GtkTextIter   *end,
                  gpointer       data)
 {
-  GtkTextView *view = data;
-  GtkTextViewAccessible *accessible;
+  GtkTextViewAccessible *accessible = data;
   gint offset, length;
 
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
-
   offset = gtk_text_iter_get_offset (start);
   length = gtk_text_iter_get_offset (end) - offset;
 
@@ -1771,10 +1783,7 @@ mark_set_cb (GtkTextBuffer *buffer,
              GtkTextMark   *mark,
              gpointer       data)
 {
-  GtkTextView *text = data;
-  GtkTextViewAccessible *accessible;
-
-  accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
+  GtkTextViewAccessible *accessible = data;
 
   /*
    * Only generate the signal for the "insert" mark, which
@@ -1929,3 +1938,22 @@ atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
   iface->get_mime_type = gail_streamable_content_get_mime_type;
   iface->get_stream = gail_streamable_content_get_stream;
 }
+
+void
+_gtk_text_view_accessible_set_buffer (GtkTextView   *textview,
+                                      GtkTextBuffer *old_buffer)
+{
+  GtkTextViewAccessible *accessible;
+
+  g_return_if_fail (GTK_IS_TEXT_VIEW (textview));
+  g_return_if_fail (old_buffer == NULL || GTK_IS_TEXT_BUFFER (old_buffer));
+
+  accessible = GTK_TEXT_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (textview)));
+  if (accessible == NULL)
+    return;
+
+  gtk_text_view_accessible_change_buffer (accessible,
+                                          old_buffer,
+                                          gtk_text_view_get_buffer (textview));
+}
+
index aacbaa3e18631739c1ba70a41d869ff78a2d8ae5..3a049ee781e15b0cd2d0cadb9c0be38698194762 100644 (file)
@@ -47,7 +47,11 @@ struct _GtkTextViewAccessibleClass
   GtkContainerAccessibleClass parent_class;
 };
 
-GType _gtk_text_view_accessible_get_type (void);
+GType           _gtk_text_view_accessible_get_type              (void);
+
+void            _gtk_text_view_accessible_set_buffer            (GtkTextView       *textview,
+                                                                 GtkTextBuffer     *old_buffer);
+
 
 G_END_DECLS
 
index a048bc9c4d8a2ed12c4d0621ffd51151dada03b2..95e63a7bdb12e6c30233274b8c78fcd2c7141d4c 100644 (file)
@@ -1479,6 +1479,7 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
                           GtkTextBuffer *buffer)
 {
   GtkTextViewPrivate *priv;
+  GtkTextBuffer *old_buffer;
 
   g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
   g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer));
@@ -1488,6 +1489,7 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
   if (priv->buffer == buffer)
     return;
 
+  old_buffer = priv->buffer;
   if (priv->buffer != NULL)
     {
       /* Destroy all anchored children */
@@ -1531,7 +1533,6 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
       if (priv->layout)
         gtk_text_layout_set_buffer (priv->layout, NULL);
 
-      g_object_unref (priv->buffer);
       priv->dnd_mark = NULL;
       priv->first_para_mark = NULL;
       cancel_pending_scroll (text_view);
@@ -1581,6 +1582,10 @@ gtk_text_view_set_buffer (GtkTextView   *text_view,
        }
     }
 
+  _gtk_text_view_accessible_set_buffer (text_view, old_buffer);
+  if (old_buffer)
+    g_object_unref (old_buffer);
+
   g_object_notify (G_OBJECT (text_view), "buffer");
   
   if (gtk_widget_get_visible (GTK_WIDGET (text_view)))